class Module {
    parent?: Module;
    id: string;
    filename: string;
    paths: string[];
    children: Module[] = [];
    exports: any = {};
    body?: DefineBody;
    opt?: DefineOptions;
    resolved: boolean = false;
    loaded: boolean = false;

    constructor(filename: string, opt: DefineOptions, body: DefineBody) {
        this.id = opt.id;
        this.filename = filename;
        this.paths = [filename];
        if (this.id !== this.filename) {
            this.paths.push(this.id);
        }
        this.opt = opt;
        this.body = body;
    }

    async resolve() {
        if (this.resolved) {
            return this;
        }
        this.resolved = true;
        if (this.opt == null) {
            throw new Error('module ' + this.id + ' cannot be resolve before define');
        }
        let promiseChildren: Promise<Module>[] = [];
        for (let i in this.opt.dependency) {
            let depId = this.opt.dependency[i];
            promiseChildren.push(zpack.resolve(depId));
        }
        this.children = await Promise.all(promiseChildren);
        return this;
    }

    load() {
        if (this.loaded) {
            return;
        }
        this.loaded = true;
        if (this.body) {
            this.body(this.require.bind(this), this.exports, this, '/', this.filename);
        }
    }

    require(filename: string) {
        return zpack.require((this.opt as DefineOptions).dependency[filename] || filename);
    }

}